<?php
namespace App\Common\Lib\Com;

use App\Common as com;
use App\Common\Lib\Com\Timer as thisTimer;

class Timer extends com\Lib\LibBase {

	/**
	 * @var int
	 */
	private static int $varItemDataIndex_TaskId = 0;

	/**
	 * @var int
	 */
	private static int $varItemDataIndex_TaskFn = 1;

	/**
	 * @var int
	 */
	private static int $varItemDataIndex_TimestampMs = 2;

	/**
	 * @var int
	 */
	private int $taskPoolsMaxId = 0;

	/**
	 * @var com\Lib\Fun\Array_\SortArray|com\Base
	 */
	private com\Lib\Fun\Array_\SortArray $poolSortArray;

	public function __construct(  ) {
		$this->poolSortArray = com\Lib\Fun\Array_\SortArray::make( [], self::$varItemDataIndex_TimestampMs, 'asc' );
		//
		parent::__construct();
	}

	/**
	 * 推入
	 * @param \Closure $taskFn
	 * @param int $timestampMs
	 * @return int 任务id
	 */
	public function push( \Closure $taskFn, int $timestampMs ):int {
		// 放入任务池
		$taskId = $this->taskPoolsMaxId++;
		// @TODO :: 优化：后期可加入快速索引，减少二分查找次数
		$this->poolSortArray->push( [
			self::$varItemDataIndex_TaskId => $taskId,
			self::$varItemDataIndex_TaskFn => $taskFn,
			self::$varItemDataIndex_TimestampMs => $timestampMs,
		] );
		//
		return $taskId;
	}

	/**
	 * 获取并删除最近时间的元素
	 * @return mixed|null [null]不存在
	 */
	public function popAsRecently(  ) {
		return $this->poolSortArray->popAsHead();
	}

	/**
	 * 获取最近时间的元素
	 * @return mixed|null [null]不存在
	 */
	public function getAsRecently(  ) {
		return $this->poolSortArray->getAsHead();
	}

	/**
	 * 删除
	 * @param int $taskId 任务id
	 * @return bool 是否删除成功。[false]数据不存在
	 */
	public function rm( int $taskId ):bool {
		foreach( $this->poolSortArray->getArrayQuote() as $taskDataKey => $taskData ){
			if( $taskData[ self::$varItemDataIndex_TaskId ] === $taskId ){
				unset( $this->poolSortArray->getArrayQuote()[ $taskDataKey ] );
				//
				return true;
			}
		}
		//
		return false;
	}

	/**
	 * 循环
	 */
	public function loop(  ) {
		while( true ){
			if( $this->loopOne() !== true ){
				// 无任务休眠1毫秒
				\Swoole\Coroutine::sleep( 0.001 );
			}
		}
	}

	/**
	 * @return bool|null [null]没有数据
	 */
	public function loopOne(  ):?bool {
		$data = $this->getAsRecently();
		// d($this->poolSortArray->getArrayQuote());
		// d($data[ self::$varItemDataIndex_TaskId ]);
		if( $data === null ){
			return null;
		}
		// 检查时间
		if( com\Lib\Fun\Time::getTimeOfMillitime() > $data[ self::$varItemDataIndex_TimestampMs ] ){
			// 执行
			call_user_func( $data[ self::$varItemDataIndex_TaskFn ] );
			// 移出
			$this->rm( $data[ self::$varItemDataIndex_TaskId ] );
			//
			return true;
		}
		//
		return null;
	}

}
